package org.iabako.client.ui.form.business.sale.make;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.*;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.HTMLPanel;
import org.iabako.client.navigation.NavigationController;
import org.iabako.client.tools.IabakoAsyncCallback;
import org.iabako.client.tools.Messages;
import org.iabako.client.ui.layout.field.LabelText;
import org.iabako.client.ui.layout.widget.dialogbox.IabakoDialogBox;
import org.iabako.client.ui.layout.widget.installment.InstallmentsDefinitionForm;
import org.iabako.client.ui.layout.widget.sale.SaleMakeTotalTable;
import org.iabako.client.ui.layout.widget.sale.SaleProductServiceInfoLine;
import org.iabako.client.ui.layout.widget.validation.ValidationMessage;
import org.iabako.shared.entity.business.Sale;
import org.iabako.shared.entity.business.SaleProductService;
import org.iabako.shared.entity.enumeration.InstallmentsType;
import org.iabako.shared.entity.enumeration.SaleStep;
import org.iabako.shared.iservice.business.SaleServiceAsync;
import org.iabako.shared.tools.GenericTools;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by jose on 22/10/14.
 */
public class SaleMakeProductServiceChoice extends SaleMakeSubForm {

    interface MyUiBinder extends UiBinder<HTMLPanel, SaleMakeProductServiceChoice> {
    }

    protected MyUiBinder binderForm = GWT.create(MyUiBinder.class);

    protected final SaleServiceAsync saleServiceAsync = SaleServiceAsync.Util.getInstance();

    @UiField
    LabelText addAnotherProductService;
    @UiField
    HTMLPanel productServicePanel;
    @UiField
    SaleProductServiceInfoLine productServiceLine;
    @UiField
    LabelText noClientPaymentNote;
    @UiField
    SaleMakeTotalTable saleTotalTable;
    @UiField
    HTMLPanel notePanel;

    CalculateTotalHandler calculateTotalHandler = new CalculateTotalHandler();
    double totalPrice;
    public double ponderedTax;

    public SaleMakeProductServiceChoice() {
        initWidget(binderForm.createAndBindUi(this));

        productServiceLine.setCalculateTotalHandler(calculateTotalHandler);
        productServiceLine.setContainer(productServicePanel);

        setAddAnotherProductServiceHandler();
        setDefaultHandlers();

        new CalculateTotalHandler().calculateTotal();
    }

    public void activateQuoteMode() {
        notePanel.setVisible(false);
    }

    @Override
    protected void restoreDraft() {
        final Sale sale = (Sale) saleMakeForm.entity;

        saleServiceAsync.getProductServiceList(sale, new IabakoAsyncCallback<List<SaleProductService>>() {
            @Override
            public void onSuccess(List<SaleProductService> result) {
                sale.setProductsServices(result);

                for (int i = 1; i < sale.getProductsServices().size(); i++) {
                    addAnotherProductServiceAction();
                }

                int i = 0;
                for (SaleProductService saleProductService : sale.getProductsServices()) {
                    SaleProductServiceInfoLine line = (SaleProductServiceInfoLine) productServicePanel.getWidget(i++);
                    line.setValues(saleProductService);
                    saleMakeForm.productServiceList.add(line.customClone());
                }

                new CalculateTotalHandler().calculateTotal();
                saleTotalTable.taxDisabled = sale.isDisableTax() != null && sale.isDisableTax();
                saleTotalTable.disableTaxAction(saleTotalTable.taxDisabled);

                saleMakeForm.saleMakePaymentDefinition.restoreDraft();

                super.onSuccess(result);
            }
        });
    }

    private void setAddAnotherProductServiceHandler() {
        addAnotherProductService.getLabel().addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                addAnotherProductServiceAction();
            }
        });
    }

    private void addAnotherProductServiceAction() {
        SaleProductServiceInfoLine productServiceLine = new SaleProductServiceInfoLine(productServicePanel);
        productServicePanel.add(productServiceLine);
        productServiceLine.setSaleWithClient(saleMakeForm.client != null || saleMakeForm.saleEnMasse);
        productServiceLine.setCalculateTotalHandler(calculateTotalHandler);
        productServiceLine.handlePriceUnit();
    }

    public void cleanServiceUndefinedInstallments() {
        for (SaleProductServiceInfoLine productServiceLine : getProductServicesLine()) {
            if (productServiceLine.getService() != null
                    && productServiceLine.getService().getInstallmentType() == InstallmentsType.undefined) {
                productServiceLine.productServiceSuggestSelectionHandler.cleanValue();
            }
        }
    }

    public void updateSaleWithClientFields() {
        for (SaleProductServiceInfoLine productServiceLine : getProductServicesLine()) {
            productServiceLine.setSaleWithClient(saleMakeForm.client != null || saleMakeForm.saleEnMasse);
        }
    }

    private class CalculateTotalHandler implements ClickHandler, KeyUpHandler, BlurHandler {

        public void onClick(ClickEvent event) {
            calculateTotal();
        }

        public void onBlur(BlurEvent event) {
            calculateTotal();
        }

        public void onKeyUp(KeyUpEvent event) {
            calculateTotal();
        }

        public void calculateTotal() {
            Double total = 0D;
            boolean isProductServiceWithTax = false;

            for (SaleProductServiceInfoLine productServiceLine : getProductServicesLine()) {

                if (productServiceLine.getProduct() == null && productServiceLine.getService() == null) {
                    continue;
                }

                double totalPerItem = 0;
                if (!GenericTools.isEmpty(productServiceLine.quantity.getDoubleValue(), productServiceLine.price.getAmountValue())) {
                    totalPerItem = productServiceLine.quantity.getDoubleValue() * productServiceLine.price.getAmountValue();
                    total += totalPerItem;
                }

                Double taxPercent;
                if (productServiceLine.getProduct() != null && (taxPercent = productServiceLine.getProduct().getTaxPercent()) != null
                        || (productServiceLine.getService() != null && (taxPercent = productServiceLine.getService().getTaxPercent()) != null)) {

                    isProductServiceWithTax = true;
                    ponderedTax += totalPerItem * taxPercent;
                }
            }
            totalPrice = total;
            if (total != 0 && isProductServiceWithTax) {
                ponderedTax /= total * 100;
            } else {
                ponderedTax = 0;
            }
            saleTotalTable.calculateAmounts(ponderedTax, totalPrice);
        }
    }

    @Override
    protected void validateForm() {

        saleMakeForm.saleWorkflow.getElement().scrollIntoView();

        boolean validate = true;
        boolean atLeastOne = false;
        List<SaleProductServiceInfoLine> toRemove = new ArrayList<SaleProductServiceInfoLine>();
        for (SaleProductServiceInfoLine productServiceLine : getProductServicesLine()) {
            if (productServiceLine.getProduct() != null || productServiceLine.getService() != null) {
                atLeastOne = true;
                if (GenericTools.isEmpty(productServiceLine.quantity.getDoubleValue())
                        || productServiceLine.quantity.getDoubleValue() <= 0) {
                    productServiceLine.quantity.addErrorMessage(productServiceLine.quantity, false, "");
                    validate = false;
                }
                if (GenericTools.isEmpty(productServiceLine.price.getAmountValue())) {
                    productServiceLine.price.addErrorMessage(productServiceLine.price, false, "");
                    validate = false;
                }

                if (validate && !validateStock(productServiceLine)) {
                    //Fields were completed, but there's no stock
                    return;
                }
            } else {
                toRemove.add(productServiceLine);
            }
        }
        for (SaleProductServiceInfoLine emptyProductService : toRemove) {
            productServicePanel.remove(emptyProductService);
        }
        if (productServicePanel.getWidgetCount() == 0) {
            addAnotherProductServiceAction();
        }

        if (!validate) {
            ValidationMessage.getFirstFromDOM().showErrorMessage(true, true, "validation_sale_make_product_service_choice_error");
        } else if (!atLeastOne) {
            ValidationMessage.getFirstFromDOM().showErrorMessage(true, true, "validation_sale_make_no_product_service_choice_error");
        } else {

            //This two lines must be execute even if no changes detected (because may be tax has been disabled)
            saleMakeForm.saleMakePaymentDefinition.saleTotalTable.taxDisabled = this.saleTotalTable.taxDisabled;
            saleMakeForm.saleMakePaymentDefinition.saleTotalTable.calculateAmounts(ponderedTax, totalPrice);

            if (!productServiceListHasChanged()) {
                handleGoTo();
                return;
            }

            updateProductServiceList();

            calculatePaymentMethodFields();

            handleGoTo();
        }
    }

    private void handleGoTo() {
        if (saleMakeForm.quoteMode) {
            saleMakeForm.goTo(SaleStep.confirmation);
            saleMakeForm.saleMakeConfirmation.enableModificationMode(true);
            saleMakeForm.saleMakeConfirmation.initialize();
        } else {
            saleMakeForm.goTo(SaleStep.how);
        }
    }

    private boolean validateStock(SaleProductServiceInfoLine productServiceLine) {
        if (saleMakeForm.quoteMode) {
            return true;
        }

        if (productServiceLine.getProduct() != null) {
            double productsInSale = saleMakeForm.saleEnMasse ?
                    saleMakeForm.clientList.size() * productServiceLine.quantity.getDoubleValue()
                    : productServiceLine.quantity.getDoubleValue();
            if (productsInSale > productServiceLine.getProduct().getQuantity()) {
                String unit = productServiceLine.getProduct().getPriceUnit().getLabel();
                unit = GenericTools.isEmpty(unit) ? " " + Messages.getLabel("stock_unit") : unit;

                String quantityString = productServiceLine.getProduct().getQuantity() == 0d
                        || productServiceLine.getProduct().getQuantity() / new Double(productServiceLine.getProduct().getQuantity()).intValue() == 1
                        ? new Double(productServiceLine.getProduct().getQuantity()).intValue() + ""
                        : GenericTools.formatAmount(productServiceLine.getProduct().getQuantity() + "");

                String message = Messages.getLabel("stock_sale_not_enough_text",
                        productServiceLine.getProduct().getName(),
                        quantityString + "", unit);

                IabakoDialogBox iabakoDialogBox = new IabakoDialogBox("stock_sale_not_enough_title", message, true, "action_forbidden_by_package_ok");
                iabakoDialogBox.setCloseOnlySimplePopup(true);
                NavigationController.getInstance().show(iabakoDialogBox);
                return false;
            }
        }
        return true;
    }

    private boolean productServiceListHasChanged() {

        if (!saleMakeForm.saleEnMasse && saleMakeForm.client == null) {
            //if there's no client, consider that product/service always change (because always oneShot paymentMethod)
            return true;
        }

        List<SaleProductServiceInfoLine> productServiceListNow = getProductServicesLine();
        for (SaleProductServiceInfoLine productServiceInfoLine : productServiceListNow) {
            if (!saleMakeForm.productServiceList.contains(productServiceInfoLine)) {
                return true;
            }
        }
        for (SaleProductServiceInfoLine productServiceInfoLine : saleMakeForm.productServiceList) {
            if (!productServiceListNow.contains(productServiceInfoLine)) {
                return true;
            }
        }
        return false;
    }

    public void updateProductServiceList() {
        saleMakeForm.productServiceList.clear();
        for (SaleProductServiceInfoLine saleProductServiceInfoLine : getProductServicesLine()) {
            saleMakeForm.productServiceList.add(saleProductServiceInfoLine.customClone());
        }
    }

    public void calculatePaymentMethodFields() {
        initializePaymentDefinitionFields();

        InstallmentsDefinitionForm installmentsDefinitionForm = saleMakeForm.saleMakePaymentDefinition.installmentsForm;
        installmentsDefinitionForm.setTotalPrice(totalPrice);

        for (SaleProductServiceInfoLine saleProductServiceInfoLine : getProductServicesLine()) {
            if (saleProductServiceInfoLine.getService() != null &&
                    saleProductServiceInfoLine.getService().getInstallmentType() == InstallmentsType.undefined) {

                //Sale with only one service undefined
                saleMakeForm.saleMakePaymentDefinition.setUndefinedFields();
            }
        }

        if (saleMakeForm.saleMakePaymentDefinition.installmentsFormPanel.isVisible()
                && saleMakeForm.saleMakePaymentDefinition.installmentsForm.installmentsType.getValue() != InstallmentsType.undefined) {
            installmentsDefinitionForm.calculateDefinedInstallments();
        }
    }

    private void initializePaymentDefinitionFields() {
        saleMakeForm.saleMakePaymentDefinition.paymentType.setVisible(true);

        saleMakeForm.saleMakePaymentDefinition.installmentsFormPanel.setVisible(false);
        saleMakeForm.saleMakePaymentDefinition.installmentsForm.initializeFields();

        if (saleMakeForm.saleEnMasse || saleMakeForm.client != null) {
            saleMakeForm.saleMakePaymentDefinition.paymentType.setValue(null);
            saleMakeForm.saleMakePaymentDefinition.paymentMethod.setVisible(false);
            saleMakeForm.saleMakePaymentDefinition.saleNote.setVisible(false);
        } else {
            saleMakeForm.saleMakePaymentDefinition.saleNote.setVisible(true);
            saleMakeForm.saleMakePaymentDefinition.saleNote.setHtmlLabel(Messages.getLabel("sale_make_one_payment_note",
                    GenericTools.formatAmount(saleMakeForm.saleMakeProductServiceChoice.totalPrice + "")));
        }
    }

    @Override
    protected void goBackAction() {
        saleMakeForm.goTo(SaleStep.who);
    }

    public List<SaleProductServiceInfoLine> getProductServicesLine() {
        List<SaleProductServiceInfoLine> productsServices = new ArrayList<SaleProductServiceInfoLine>();
        for (int i = 0; i < productServicePanel.getWidgetCount(); i++) {
            productsServices.add((SaleProductServiceInfoLine) productServicePanel.getWidget(i));
        }
        return productsServices;
    }
}
